﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting.Contexts;
using System.Text;
using MaxZhang.EasyEntities.Attribute;
using MaxZhang.EasyEntities.Dynamic;
using MaxZhang.EasyEntities;

namespace MaxZhang.EasyEntities.Dynamic.Aop
{
 
    /// <summary>
    /// C# 定义装饰对象AOP注入器 
    /// </summary>
    public class DynamicProxy
    {
        #region 私有字段
            private const string AssemblyName = "TEMP_DYNAMIC_ASSEMBLY";
            private const string ClassName = "TEMP_CLASS_NAME";
            private static TypeBuilder typeBuilder;
            private static FieldBuilder target;
        #endregion

        /// <summary>
        /// 向方法注入多个拦截器
        /// 注入方法加入方法拦截器BeforeDecoratorAttribute和BeforeDecoratorAttribute
        /// BeforeDecorator
        /// </summary>
        /// <param name="proxy">代理对象</param>
        /// <param name="target">被拦截的对象实例</param>
        /// <param name="method">被拦截对象方法</param>
        /// <param name="parameters">被拦截方法参数</param>
        /// <returns>被方法返回值</returns>
        public static object InjectHandlerMethod(object proxy, object target, MethodBase method, object[] parameters)//, DecoratorBaseAttribute[] attributes)
        {
     
            #region 获取拦截器
            
          
                //从对象方法中取得拦截器
                var attributes = (InterceptorBaseAttribute[])method.GetCustomAttributes(
                                                    typeof(InterceptorBaseAttribute), true
                                                  );
                if ((method.Name.StartsWith("get_") || method.Name.StartsWith("set_")) && attributes.Length==0)
                {
                    var propertyName= method.Name.Substring(4);
                    var propertyInfo= target.GetType().GetProperty(propertyName);
                    if (propertyInfo!=null)
                    {
                       attributes= propertyInfo.GetCustomAttributes(typeof(InterceptorBaseAttribute), true) as InterceptorBaseAttribute[];
                    }
                }

                if (attributes.Length == 0)        //对象本身没有DecoratorBase特性（拦截器）
                {
                    //从接口中取得拦截器
                   
                    Type objIface=null;
                    var objIfaces = target.GetType().GetInterfaces();  
                    if(objIfaces.Length > 0)       //如果对象有接口
                    {
                        objIface = objIfaces[0];   //得到对象接口
                        MethodInfo im= objIface.GetMethod(method.Name);
                        if(im!=null)               //得到被拦截的接口方法
                        {
                            //得到被拦截的接口方法的所有拦截器
                           var mAttribs= (InterceptorBaseAttribute[])im.GetCustomAttributes(typeof(InterceptorBaseAttribute), true);
                           attributes = mAttribs;
                        }
                    }
                }

                
                //（加载AopTable配置）对象和接口中都没有拦截器则从AopTable中取得
                //attributes
                if (attributes.Length == 0)
                {
                   string className= target.GetType().FullName;
                   string methodName = method.Name;
                   attributes = AopTabel.Aspects.GetInterceptors(className, methodName);
                }

            #endregion

            
            ProcessContext beforeContext = new ProcessContext() { Proxy= proxy , Target = target, Method = method, Parameters = parameters, ReturnValue = null };

            #region 调用拦截方法,前后执行拦截器方法

                //是否进入下一个函数
                bool theNext = true;                  
                
                //返回值
                object returnValue = null;

                //BeforeInterceptor调用目标函数前
                foreach (InterceptorBaseAttribute attribute in attributes)
                {
                    if (attribute is BeforeInterceptorAttribute)
                    {
                        theNext = theNext && attribute.Process(beforeContext);

                        if (beforeContext.ReturnValue != null)
                            returnValue= beforeContext.ReturnValue;
                    }
                }

                //如果有false就不进入下一个函数  
                if (theNext != false)                                           
                {
                    //这里调用目标对象函数
                    //DynamicMethodExecutor methoder = new DynamicMethodExecutor(target.GetType().GetMethod(method.Name));
                    //returnValue = methoder.Execute(target, parameters);

                    returnValue =target.GetType().GetMethod(method.Name).Invoke(target, parameters);

                    ProcessContext afterContext = new ProcessContext() { Proxy = proxy, Target = target, Method = method, Parameters = parameters, ReturnValue = returnValue };

                   //AfterInterceptor调用目标函数后
                    foreach (InterceptorBaseAttribute attribute in attributes)
                        if (attribute is AfterInterceptorAttribute)
                            attribute.Process(afterContext);

                }
            #endregion

            return returnValue;
        }

        /// <summary>
        /// 动态创建对象代理
        /// </summary>
        /// <typeparam name="TModel">代理类型</typeparam>
        /// <returns>指定类型的代理对象</returns>
        public static TModel CreateProxy<TModel>() where TModel : class
        {
            object target= Activator.CreateInstance(typeof (TModel));
            if (target == null)
                throw new NullReferenceException("创建对象时错误！");
            return (TModel)Create(target);
        }

        /// <summary>
        /// 动态创建对象代理
        /// </summary>
        /// <typeparam name="TModel">代理类型</typeparam>
        /// <param name="paramers">构造参数</param>
        /// <returns>指定类型的代理对象</returns>
        public static TModel CreateProxy<TModel>(params object[] paramers)
        {
            object target = Activator.CreateInstance(typeof(TModel),paramers);
            if (target == null)
                throw new NullReferenceException("创建对象时错误！");
            return (TModel)Create(target);
        }

       /// <summary>
        /// 动态创建对象代理
       /// </summary>
        /// <typeparam name="TModel">代理类型</typeparam>
        /// <param name="target">已经定义的代理对象</param>
        /// <returns>指定源对象的代理对象</returns>
        public static TModel CreateProxy<TModel>(object target)
        {
            if (target == null)
                throw new NullReferenceException("创建对象时错误！");
            return (TModel)Create(target);
        }

      

        private static object Create(object target)
        {
            Type proxyType = EmiProxyType(target.GetType());
            return Activator.CreateInstance(proxyType, new object[] { target});
        }

        protected static CacheManager<Type> cacheManager=new CacheManager<Type>(
            new SimpleCache<Type>(),null);

        //动态创建新的代理类型
        private static Type EmiProxyType(Type targetType)
        {

            AppDomain currentDomain = System.Threading.Thread.GetDomain();
            AssemblyName assemblyName = new AssemblyName();
            assemblyName.Name = AssemblyName;
            AssemblyBuilder assemblyBuilder =currentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder modBuilder = assemblyBuilder.DefineDynamicModule(ClassName);
            //代理类型名
            string typeName = assemblyName + "__Proxy" + targetType.Name;
            Type type = modBuilder.GetType(typeName);
            if (type == null)
            {
                type = cacheManager.Get(typeName);
                if (type != null)
                {
                    return type;
                }
                else
                {
                    typeBuilder = modBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public,
                                                        targetType);

                    target = typeBuilder.DefineField("target", targetType, FieldAttributes.Private);

                    //生成代理类型构造器的LI代码
                    EmitConstructor(typeBuilder, target);

                    List<PropertyInfo> propertys = GetTypePropertys(targetType);
                    PropertyBuilder[] propertiesBuilders = new PropertyBuilder[propertys.Count];
                    for (int i = 0; i < propertys.Count; i++)
                    {
                        GeneratePropertyImplementation(typeBuilder, propertys[i], ref propertiesBuilders[i]);
                    }


                    MethodInfo[] methods;
                    List<MethodInfo> pMethods = GetTypeMethods(targetType);
                    methods = pMethods.ToArray();



                    foreach (MethodInfo m in methods)
                    {
                        //var attributes = (InterceptorBaseAttribute[])m.GetCustomAttributes(
                        //                          typeof(InterceptorBaseAttribute), true
                        //                        );
                        //if (attributes.Length ==0)
                        //    continue;

                        if (m.Name == "Dispose")
                             continue;
                        var methodBuilder = EmitProxyMethod(m, typeBuilder); //生成接口方法入口(及代理与对象一致)的IL代码

                        #region 生成属性

                        if (m.Name.StartsWith("set_") || m.Name.StartsWith("get_"))
                        {
                            foreach (PropertyBuilder property in propertiesBuilders)
                            {


                                if (property == null)
                                {
                                    break;
                                }

                                if (!property.Name.Equals(m.Name.Substring(4)))
                                {
                                    continue;
                                }

                                if (methodBuilder.Name.StartsWith("set_"))
                                {
                                    property.SetSetMethod(methodBuilder);
                                    break;
                                }
                                else
                                {
                                    property.SetGetMethod(methodBuilder);
                                    break;
                                }
                            }
                            // 如果方法以set_或get_开头, 则遍历所有的属性, 如果名称相同则设置属性的set/get方法.
                        }

                        #endregion
                    }

                    var newCacheType=  typeBuilder.CreateType(); //创建代理类型
                    
                    type = newCacheType;
                    cacheManager.Set(typeName,newCacheType);
                 
                }
            
            }
            else
            {
                cacheManager.Set(typeName, type);
            }
            return type;
        }

        //得到类型的方法列表
        private static List<MethodInfo> GetTypeMethods(Type targetType)
        {
            var objMethods = targetType.GetMethods();
            List<MethodInfo> pMethods = new List<MethodInfo>();
            foreach (var m in objMethods)
            {
                //过滤object类继承来的方法和事件方法，只保留基类方法和属性方法
                if (m.DeclaringType != typeof(object) && !m.Name.StartsWith("add_") && !m.Name.StartsWith("remove_") && !m.Name.Equals("NotifyPropertyChanged"))
                {
                    pMethods.Add(m);
                }
            }
            return pMethods;
        }

        //得到类型的属性列表
        private  static List<PropertyInfo> GetTypePropertys(Type targetType)
        {
            var oPropertys = new List<PropertyInfo>();

            var objPropertys = targetType.GetProperties();
            
            foreach (var p in objPropertys)
            {
                  //var attributes = (InterceptorBaseAttribute[])p.GetCustomAttributes(
                  //                                  typeof(InterceptorBaseAttribute), true
                  //                                );
                  //if (attributes.Length>0)
                    oPropertys.Add(p);
            }
            return oPropertys;
        }


        //动态生成代理方法IL代码
        private static MethodBuilder EmitProxyMethod(MethodInfo method, TypeBuilder typeBuilder)
        {
                // 1、定义动态IL生成对象 
                Type[] paramTypes = GetParameterTypes(method);
                MethodAttributes atts = MethodAttributes.Public | MethodAttributes.Virtual;
                if (method.Name.StartsWith("set_") || method.Name.StartsWith("get_"))
                {
                    atts = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual;
                }

                MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name,
                                                                       atts, method.ReturnType,
                                                                       paramTypes);
                ILGenerator il = methodBuilder.GetILGenerator();
                LocalBuilder parameters = il.DeclareLocal(typeof (object[]));
                il.Emit(OpCodes.Ldc_I4, paramTypes.Length);
                il.Emit(OpCodes.Newarr, typeof (object));
                il.Emit(OpCodes.Stloc, parameters);


                #region AddGenericTypes
                bool isvoid = method.ReturnType.ToString() == "System.Void";
                Type[] gtypes = null;
                if (method.IsGenericMethod)//顶他个肺是泛型方法
                {
                    gtypes = method.GetGenericArguments();//得到泛型参类型
                    il.Emit(OpCodes.Ldc_I4, gtypes.Length);//加载数组长度
                    il.Emit(OpCodes.Newarr, typeof(Type));//定义数组,并保存以下局部变量中
                    if (!isvoid)
                        il.Emit(OpCodes.Stloc_S, 4);
                    else
                        il.Emit(OpCodes.Stloc_3);
                    for (int i = 0; i < gtypes.Length; i++)//这下把TM后面的运行时类型挖出来放到数据组中
                    {
                        if (!isvoid)//加载相关局部变量
                            il.Emit(OpCodes.Ldloc_S, 4);
                        else
                            il.Emit(OpCodes.Ldloc_3);
                        il.Emit(OpCodes.Ldc_I4, i);//设置索引
                        il.Emit(OpCodes.Ldtoken, gtypes[i]);//封送类型
                        var callmethod = typeof(Type).GetMethod("GetTypeFromHandle"
                            , new Type[] { typeof(RuntimeTypeHandle) });
                        il.Emit(OpCodes.Call, callmethod);//把运行时类型拖出来
                        il.Emit(OpCodes.Stelem_Ref);//把类型放进袋子里

                    }
                }
              

                #endregion



                for (int i = 0; i < paramTypes.Length; i++)
                {
                    il.Emit(OpCodes.Ldloc, parameters);
                    il.Emit(OpCodes.Ldc_I4, i);
                    il.Emit(OpCodes.Ldarg, i + 1);

                    if (paramTypes[i].IsValueType || paramTypes[i].IsGenericParameter || paramTypes[i].IsGenericType)
                        il.Emit(OpCodes.Box, paramTypes[i]);

                    il.Emit(OpCodes.Stelem_Ref);
                }
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, target);
                il.EmitCall(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod"), null);
                il.Emit(OpCodes.Ldloc, parameters);


                //// 3、执行“横切”函数 
                il.Emit(OpCodes.Call, typeof(DynamicProxy).GetMethod("InjectHandlerMethod"));

                if (method.ReturnType == typeof (void))
                    il.Emit(OpCodes.Pop);
                else 
                {
                    if (method.ReturnType.IsValueType || method.ReturnType.IsGenericType || method.ReturnType.IsGenericParameter)
                    {
                        il.Emit(OpCodes.Unbox_Any, method.ReturnType);
                        //il.Emit(OpCodes.Ldind_Ref);
                    }
                    else
                    {
                        il.Emit(OpCodes.Castclass, method.ReturnType);
                    }
                }
                il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        // 属性的实现.
        private static void GeneratePropertyImplementation(TypeBuilder typeBuilder,
              PropertyInfo property, ref PropertyBuilder propertyBuilder)
        {
            propertyBuilder = typeBuilder.DefineProperty(
            property.Name, property.Attributes, property.PropertyType, null);
            // 通过调用DefindProperty方法来产生属性的实现部分.
        }



        // 通过动态生成的MSIL形成构造方法 
        private static void EmitConstructor(TypeBuilder typeBuilder, FieldBuilder target)
        {
            Type objType = Type.GetType("System.Object");
            ConstructorInfo objCtor = objType.GetConstructor(new Type[0]);
            ConstructorBuilder pointCtor = typeBuilder.DefineConstructor(MethodAttributes.Public,
            CallingConventions.Standard, new Type[] { typeof(object) });

            ILGenerator ctorIL = pointCtor.GetILGenerator();
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Call, objCtor);
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Ldarg_1);
            ctorIL.Emit(OpCodes.Stfld, target);

            ctorIL.Emit(OpCodes.Ret);
        }


        //得到方法的参数类型列表
        private static Type[] GetParameterTypes(MethodInfo method)
        {
            if (method == null) return null;
            Type[] types = new Type[method.GetParameters().Length];
            int i = 0;
            foreach (ParameterInfo parameter in method.GetParameters())
                types[i++] = parameter.ParameterType;
            return types;
        }




    } 



}
